/*
 * Class name: PlayerDAOImpl.java
 * Version: 1.0
 * Date: 9.10.2013
 */
package cz.muni.fi.pa165.soccergamesarchive.persistencelayer.daos;

import cz.muni.fi.pa165.soccergamesarchive.businesslayer.dtos.PlayerDetailDTO;
import cz.muni.fi.pa165.soccergamesarchive.errorhandling.ErrorHandler;
import cz.muni.fi.pa165.soccergamesarchive.persistencelayer.entities.Player;
import cz.muni.fi.pa165.soccergamesarchive.persistencelayer.querybuilders.entity.PlayerCriteriaQueryBuilder;
import cz.muni.fi.pa165.soccergamesarchive.validators.ValidatorTest;
import java.util.List;
import java.util.Map;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

import static cz.muni.fi.pa165.soccergamesarchive.errorhandling.ErrorHandler.createErrorMessage;
import static cz.muni.fi.pa165.soccergamesarchive.validators.PlayerValidator.validatePlayer;

/**
 *
 * @author Michal Ďuriš
 */
@TransactionAttribute(TransactionAttributeType.MANDATORY)
@Stateless
public class PlayerDAOImpl implements PlayerDAO {

    @PersistenceContext(unitName = "SoccerGamesArchivePersistenceUnit")
    private EntityManager entityManager;

    private final PlayerCriteriaQueryBuilder queryBuilder = new PlayerCriteriaQueryBuilder(
            Player.class);

    public PlayerDAOImpl() {
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public Player addPlayer(Player player) throws RuntimeException {

        validatePlayer(player,
                ValidatorTest.NULL_TEST,
                ValidatorTest.CORRECT_RECORD_TEST);

        entityManager.persist(player);

        return player;
    }

    @Override
    public Player changePlayer(Player player) throws RuntimeException {

        validatePlayer(player, ValidatorTest.FULL_TEST);

        return entityManager.merge(player);
    }

    @Override
    public void removePlayer(Player player) throws RuntimeException {

        validatePlayer(player,
                ValidatorTest.NULL_TEST,
                ValidatorTest.ID_TEST);

        player.getTeam().getPlayers().remove(player);

        entityManager.merge(player.getTeam());
    }

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    @Override
    public List<Player> getAllPlayers() throws RuntimeException {

        return entityManager.createNamedQuery("Player.getAllPlayers",
                Player.class).getResultList();
    }

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    @Override
    public List<Player> getLimitedNumberOfPlayers(int offset, int limit,
                                                  Map<String, Object> filterMap,
                                                  Map<String, Boolean> orderMap)
            throws RuntimeException {

        if (offset < 0 || limit <= 0) {
            throw new IllegalArgumentException(createErrorMessage(
                    this.getClass().getName(), ErrorHandler.ILLEGAL_VALUE_ERROR));
        }

        return queryBuilder.createEntitySelectCriteriaQuery(entityManager,
                filterMap, orderMap).setFirstResult(offset).setMaxResults(limit)
                .getResultList();
    }

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    @Override
    public Player getPlayerById(Long id) throws RuntimeException {

        if (id == null || id < 1) {
            throw new IllegalArgumentException(createErrorMessage(
                    this.getClass().getName(), ErrorHandler.ILLEGAL_VALUE_ERROR));
        }

        return entityManager.find(Player.class, id);
    }

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    @Override
    public PlayerDetailDTO getPlayerDetail(Long id) throws RuntimeException {

        if (id == null || id < 1) {
            throw new IllegalArgumentException(createErrorMessage(
                    this.getClass().getName(), ErrorHandler.ILLEGAL_VALUE_ERROR));
        }

        return entityManager.createNamedQuery("Player.getPlayerDetail",
                PlayerDetailDTO.class).setParameter("playerID", id)
                .getSingleResult();
    }

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    @Override
    public int getFilteredPlayersCount(Map<String, Object> filterMap) throws
            RuntimeException {

        return queryBuilder.createEntityCountCriteriaQuery(entityManager,
                filterMap).getSingleResult().intValue();
    }

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    @Override
    public List<Player> findPlayer(String firstName, String lastName) throws
            RuntimeException {

        if ((firstName == null || firstName.equals(""))
                && (lastName == null || lastName.equals(""))) {
            throw new IllegalArgumentException(createErrorMessage(
                    this.getClass().getName(), ErrorHandler.ILLEGAL_VALUE_ERROR));
        }

        if (firstName == null) {
            firstName = "";
        }

        if (lastName == null) {
            lastName = "";
        }

        TypedQuery<Player> playerTypedQuery = entityManager.createNamedQuery(
                "Player.findPlayer", Player.class);

        playerTypedQuery.setParameter("firstName",
                firstName.trim().toLowerCase() + "%");
        playerTypedQuery.setParameter("lastName",
                lastName.trim().toLowerCase() + "%");

        return playerTypedQuery.getResultList();
    }

}
